package owg.util.editor2d.entity;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import owg.util.editor2d.entity.SP.FileList.FileTypes;
/**Container class for various annotations indicating special treatment for parameters in the WorldEditor.
 * Multiple annotations may be used where this makes sense.*/
public class SP
{
    public interface StringProcessor
    {
	public String modify(String str);
    }

    @Retention(RetentionPolicy.RUNTIME)
    /**Marks that the following parameter should be normalized*/
    public @interface Normalized {}
    @Retention(RetentionPolicy.RUNTIME)
    /**Marks that the following parameter must take as value the name of one of the subfolders or files of the given folder.  The search is not recursive.
     * Optionally, the file names may be transformed using an instance of the stringProcessor class. The class must define a no-args constructor. This will 
     * happen *after* any eventual filter is applied, allowing filters to work on file extensions even in the case where they are stripped by the string processor.*/
    public @interface FileList {
	enum FileTypes {FILES(true, false), FOLDERS(false, true), FILES_AND_FOLDERS(true, true);
	final boolean files, folders;
	FileTypes(boolean files, boolean folders){this.files = files; this.folders = folders;}
	public boolean allowFiles() {return files;}
	public boolean allowFolders() {return folders;}
	}
	String folder(); 
	FileTypes fileTypes();
	Class<? extends StringProcessor> stringProcessor();}
    @Retention(RetentionPolicy.RUNTIME)
    /**Marks that the following parameter specifies an angle.
     * This implies that the value should be presented to the user using degrees, although the internal representation is radians.
     * TODO this does not work.*/
    public @interface Angle {}
    @Retention(RetentionPolicy.RUNTIME)
    /**Marks that the following parameter is a python script. Applies to String editors.
     * TODO this does not work.*/
    public @interface Python {}
    @Retention(RetentionPolicy.RUNTIME)
    /**For objects chosen from lists, this marks that the following parameter should match the regex given in the value.
     * Note the exception that Enums cannot be filtered.
     * Also note that null values are always passed unless the SP.NonNull annotation is also present.<br/>
     * For free text input strings, all substrings matching the regex given in the value will be removed from the string.
     * Note that for string lists or arrays, the input may be split according to a split delimiter(Delimiters.split())
     * before being subject to filtering. Example filter: "generic.*" for anything starting with "generic".*/
    public @interface Filter {String value();}
    @Retention(RetentionPolicy.RUNTIME)
    /**Marks that the following parameter may be null.
     * This is only defined for objects that are chosen from lists; Text fields or boolean inputs cannot take the value null.*/
    public @interface AllowNull {}
    @Retention(RetentionPolicy.RUNTIME)
    /**Marks that the following parameter's input should be split up according to the split regex and 
     * displayed with the display delimiter between elements. If retainEmptyString is false, then
     * empty strings(after filtering) in the input will not be inserted into the resulting list or array.
     * By default(without this annotation), empty strings are retained, and the input string is not split.*/
    public @interface Delimiters {String split(); String display(); boolean retainEmptyStrings();}

    private Annotation[] annotationSet;

    public SP(Annotation[] set)
    {
	annotationSet = set;
    }

    public boolean contains(Class<?> spType)
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		if(spType.isInstance(annotationSet[i]))
		    return true;
	    }
	}
	return false;
    }
    /**Returns the string processor class associated with a {@link FileList} annotation.*/
    public Class<? extends StringProcessor> getStringProcessor()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof FileList)
		    return ((FileList) a).stringProcessor();
	    }
	}
	return null;
    }
    /**Returns the folder to search in, if it exists, null otherwise. (use the SP.FileList annotation to define this)*/
    public String getFolder()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof FileList)
		    return ((FileList) a).folder();
	    }
	}
	return null;
    }
    /**Returns the folder to search in, if it exists, null otherwise. (use the SP.FileList annotation to define this)*/
    public FileTypes getFileTypes()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof FileList)
		    return ((FileList) a).fileTypes();
	    }
	}
	return null;
    }
    /**Returns the value of the Filter modifier, if it exists, null otherwise. (use the SP.Filter annotation to define this)*/
    public String getFilter()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof Filter)
		    return ((Filter) a).value();
	    }
	}
	return null;
    }

    /**Returns the split delimiter regex for parsing this list. This should be a superset of {@link #getDisplayDelimiter()}:
     * For example, if the display delimiter is ", ", then the regex should be able to recognise that string as a split delimiter also.
     * Example: "[^A-Za-z0-9_]+" will split on all substrings consisting of non-alphanumeric characters(or underscore).*/
    public String getSplitDelimiter()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof Delimiters)
		    return ((Delimiters) a).split();
	    }
	}
	return null;
    }
    /**The delimiter between elements in the list when displaying it in the editor. For example: ", "*/
    public String getDisplayDelimiter()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof Delimiters)
		    return ((Delimiters) a).display();
	    }
	}
	return null;
    }
    /**Whether empty strings should be retained in the list. 
     * For example, the string "a , , b" might become ["a", "", "b"] if this is true, or ["a", "b"] if this is false.*/
    public boolean shouldRetainEmptyStrings()
    {
	if(annotationSet != null)
	{
	    for(int i = 0; i < annotationSet.length; i++)
	    {
		Annotation a = annotationSet[i];
		if(a instanceof Delimiters)
		    return ((Delimiters) a).retainEmptyStrings();
	    }
	}
	return true;
    }
}
